﻿using Com.Lancetinc.Evs.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Com.Lancetinc.Evs.Helpers
{
    public static class AppConfigHelper
    {
        private static readonly Dictionary<string, EndoscopicConfig> endoscopicConfigByTypeCode = new();
        private static readonly Dictionary<string, VideoConfig> videoConfigByTypeCode = new();
        private static readonly Dictionary<string, VideoFlipConfig> videoFlipConfigByTypeCode = new();

        public static int GetShelfLifeMonthsByHcSerialNo(string hcSerialNo)
        {
            var config = GetEndoscopicConfigByHcSerialNo(hcSerialNo);
            return config?.ShelfLifeMonths ?? 24;
        }

        public static EndoscopicConfig GetEndoscopicConfig(string typeCode)
        {
            if (endoscopicConfigByTypeCode.ContainsKey(typeCode))
            {
                return endoscopicConfigByTypeCode[typeCode];
            }
            var prefix = "m=" + typeCode + ",";
            var configLine = GetFirstConfigLine(prefix);
            if (configLine == null)
            {
                return null;
            }
            var config = ParseEndoscopicConfig(configLine.Substring(2));
            if (config != null)
            {
                endoscopicConfigByTypeCode[typeCode] = config;
            }
            return config;
        }

        public static VideoConfig GetVideoConfig(string typeCode)
        {
            if (videoConfigByTypeCode.ContainsKey(typeCode))
            {
                return videoConfigByTypeCode[typeCode];
            }
            var prefix = "v=" + typeCode + ",";
            var configLine = GetFirstConfigLine(prefix);
            if (configLine == null)
            {
                return null;
            }
            var config = ParseVideoConfig(configLine.Substring(2));
            if (config != null)
            {
                videoConfigByTypeCode[typeCode] = config;
            }
            return config;
        }

        public static VideoFlipConfig GetVideoFlipConfig(string typeCode)
        {
            if (videoFlipConfigByTypeCode.ContainsKey(typeCode))
            {
                return videoFlipConfigByTypeCode[typeCode];
            }
            var prefix = "f=" + typeCode + ",";
            var configLine = GetFirstConfigLine(prefix);
            if (configLine == null)
            {
                return null;
            }
            var config = ParseVideoFlipConfig(configLine.Substring(2));
            if (config != null)
            {
                videoFlipConfigByTypeCode[typeCode] = config;
            }
            return config;
        }

        public static string GetTypeCodeByHcSerialNo(string hcSerialNo)
        {
            if (string.IsNullOrEmpty(hcSerialNo) || hcSerialNo.Length < 2)
            {
                return null;
            }
            return hcSerialNo.Substring(0, 2);
        }

        public static EndoscopicConfig GetEndoscopicConfigByHcSerialNo(string hcSerialNo)
        {
            var typeCode = GetTypeCodeByHcSerialNo(hcSerialNo);
            return typeCode != null ? GetEndoscopicConfig(typeCode) : null;
        }

        public static string GetWhiteBalanceConfig(String typeCode)
        {
            var key = "wb." + typeCode + "=";
            return GetFirstConfigLine(key)?.Substring(key.Length).Trim();
        }

        private static EndoscopicConfig ParseEndoscopicConfig(string configString)
        {
            var index = configString.LastIndexOf(',');
            var crc = configString.Substring(index + 1);
            configString = configString.Substring(0, index);
            var calculatedCrc = Md5Utils.Encrypt(configString).Substring(10, 5);
            if (crc != calculatedCrc)
            {
                Console.WriteLine($"invalid crc. accept:{calculatedCrc}, actual:{crc}");
                return null;
            }
            string[] ss = configString.Split(',');
            if (ss.Length != 7)
            {
                Console.WriteLine("invalid config. count of columns not 7");
                return null;
            }
            return new EndoscopicConfig
            {
                TypeCode = ss[0],
                Model = ss[1],
                HorizontalResolution = int.Parse(ss[2]),
                VerticalResolution = int.Parse(ss[3]),
                VideoFormat = ss[4],
                Reusable = "1".Equals(ss[5]),
                ShelfLifeMonths = int.Parse(ss[6])
            };
        }

        private static VideoConfig ParseVideoConfig(string configString)
        {
            var index = configString.LastIndexOf(',');
            var crc = configString.Substring(index + 1);
            configString = configString.Substring(0, index);
            var calculatedCrc = Md5Utils.Encrypt(configString).Substring(10, 5);
            if (crc != calculatedCrc)
            {
                Console.WriteLine($"check crc failed,expect={calculatedCrc},actual={crc}");
                return null;
            }
            string[] ss = configString.Split(',');
            if (ss.Length != 3)
            {
                return null;
            }
            return new VideoConfig(int.Parse(ss[1]), int.Parse(ss[2]));
        }


        /// <summary>
        /// f=型号,水平镜像,垂直镜像
        /// </summary>
        /// <param name="configString"></param>
        /// <returns></returns>
        private static VideoFlipConfig ParseVideoFlipConfig(string configString)
        {
            var index = configString.LastIndexOf(',');
            var crc = configString.Substring(index + 1);
            configString = configString.Substring(0, index);
            var calculatedCrc = Md5Utils.Encrypt(configString).Substring(10, 5);
            if (crc != calculatedCrc)
            {
                Console.WriteLine($"check crc failed,expect={calculatedCrc},actual={crc}");
                return null;
            }
            string[] ss = configString.Split(',');
            if (ss.Length != 3)
            {
                return null;
            }
            return new VideoFlipConfig(ParseBool(ss[1]), ParseBool(ss[2]));
        }

        private static bool ParseBool(string str)
        {
            if (string.IsNullOrEmpty(str))
                return false;

            if (bool.TryParse(str, out var result))
                return true;

            string[] booleanStringOff = { "off", "no" };
            if (booleanStringOff.Contains(str, StringComparer.OrdinalIgnoreCase))
                return false;

            string[] booleanStringOn = { "on", "yes" };
            if (booleanStringOn.Contains(str, StringComparer.OrdinalIgnoreCase))
                return true;

            return str != "0";
        }

        public static string GetFirstConfigLine(string linePrefix)
        {
            var lines = LoadConfig(false);
            if (lines == null)
            {
                return null;
            }
            var line = lines.FirstOrDefault(x => x.StartsWith(linePrefix));
            return line?.Trim();
        }

        internal static string[] LoadConfig(bool includeComment = true)
        {
            var path = AppDomain.CurrentDomain.BaseDirectory;
            path = Path.Combine(path, "config.ini");
            if (!File.Exists(path))
            {
                return null;
            }
            var lines = File.ReadAllLines(path);
            if (!includeComment)
                lines = lines.Where(x => !x.StartsWith("#")).ToArray();
            return lines;
        }
    }
}
